package Servers

import (
	. "GameLogic"
	"PBMessage"
	"SGNet"
	. "Servers/BaseServer"
	"fmt"
	//"fmt"

	proto "misc/protobuf/proto"
	log "misc/seelog"
	"time"

	. "misc/EventSystem"
)

const (
	SCENETICK_Tick  = 3000000000
	SCENETICK_Logic = 1000000000 / 30
)

type SceneServer struct {
	UUID string
	BaseServer
	Players map[int64]IPlayer
	//Update Time
	lastSceneTickTime int64
	subSceneTickTime  int64
	addTickTime       int64
	addLogicTime      int64

	LogicScene *GameScene
	GateServer IServer

	IsRuning bool

	EnterSceneOKNumber int
}

func NewSceneServer(uuid string, hallPlayers []*HallPlayer, readyPlayers []*PBMessage.ReadRoomPlayer, mapId int32) *SceneServer {
	retSceneServer := &SceneServer{
		UUID:    uuid,
		Players: make(map[int64]IPlayer),
	}
	retSceneServer.BaseServer.New()
	retSceneServer.Init(hallPlayers, readyPlayers)
	retSceneServer.LogicScene = NewGameScene(mapId, retSceneServer.Players, retSceneServer.UUID)
	retSceneServer.IsRuning = true
	retSceneServer.Run()
	log.Info("新建游戏场景", retSceneServer.UUID)
	GlobalEventManager.AddEventHandler("GameScene.Player.EnterOK", retSceneServer.PlayerEnterSceneOKHandler)
	return retSceneServer
}

func (this *SceneServer) PlayerEnterSceneOKHandler(args ...interface{}) {
	this.EnterSceneOKNumber++
	if this.EnterSceneOKNumber >= len(this.Players) {
		this.LogicScene.Load()
	}
}

func (sceneServer *SceneServer) Init(hallPlayers []*HallPlayer, readyPlayers []*PBMessage.ReadRoomPlayer) {
	sceneServer.lastSceneTickTime = time.Now().UnixNano()
	for i := 0; i < len(hallPlayers); i++ {
		scenePlayer := &ScenePlayer{
			AccountModel: hallPlayers[i].Account,
			Sess:         hallPlayers[i].Sess,
			curServer:    sceneServer,
			ReadyPlayer:  readyPlayers[i],
			UserId:       hallPlayers[i].GetUserId(),
			IsRobotValue: hallPlayers[i].IsRobotValue,
			AIUnit:       hallPlayers[i].AIUnit,
		}
		if scenePlayer.AIUnit != nil {
			scenePlayer.AIUnit.PlayerUUID = scenePlayer.UserId
			fmt.Println("SceneServer Init", scenePlayer.AIUnit.PlayerUUID)
		}
		if scenePlayer.Sess != nil {
			scenePlayer.Sess.UserData = scenePlayer
			scenePlayer.Sess.SetAliveTime(int64(time.Second * 5))
		}
		sceneServer.Players[scenePlayer.UserId] = scenePlayer
	}
	sceneServer.AddNetHandler(PBMessage.PBID_CS_GameSceneTick, func(msg *SGNet.Message) {})
	sceneServer.AddCommandHandler(CommonID_ClientLost, sceneServer.Commond_ClientLostHandler)
	sceneServer.LoadHandlers()

}

func (sceneServer *SceneServer) GetServerType() int {
	return Server_Scene
}

func (sceneServer *SceneServer) Run() {
	go sceneServer.Loop()
}

func (sceneServer *SceneServer) Loop() {
	for sceneServer.IsRuning {
		sceneServer.BaseServer.ProcessMessages()
		if sceneServer.IsRuning == false {
			return
		}
		sceneServer.subSceneTickTime = time.Now().UnixNano() - sceneServer.lastSceneTickTime
		sceneServer.addTickTime += sceneServer.subSceneTickTime
		sceneServer.addLogicTime += sceneServer.subSceneTickTime
		if sceneServer.addTickTime >= SCENETICK_Tick {
			sceneServer.addTickTime = 0
		}
		if sceneServer.addLogicTime >= SCENETICK_Logic {
			sceneServer.UpdateLogic(float64(sceneServer.subSceneTickTime) / float64(time.Second))
			sceneServer.addLogicTime = 0
		}
		sceneServer.lastSceneTickTime = time.Now().UnixNano()
		time.Sleep(time.Millisecond)
	}
}

func (sceneServer *SceneServer) UpdateLogic(dt float64) {
	for _, player := range sceneServer.Players {
		if player.(*ScenePlayer).AIUnit != nil {
			player.(*ScenePlayer).AIUnit.Update()
		}
	}
	sceneServer.LogicScene.Update(dt)
}

func (sceneServer *SceneServer) RemovePlayer(userId int64) {
	delete(sceneServer.Players, userId)
}

func (sceneServer *SceneServer) Destory() {
	sceneServer.IsRuning = false
	backHall := &PBMessage.SC_GameEndBackHall{}
	backHall.Exp = proto.Int32(0)
	backHall.Gold = proto.Int32(0)
	log.Info(sceneServer.Players)
	for _, player := range sceneServer.Players {
		if player.GetSeesion() != nil {
			player.GetSeesion().SendPacket(PBMessage.PBID_SC_GameEndBackHall, backHall)
		}
	}

	sceneServer.LogicScene.Destory()
	sceneServer.GateServer.PushMessage(CommondMessage(CommonID_DestoryGameScene, "sceneId", sceneServer.UUID))
}

func (sceneServer *SceneServer) Commond_ClientLostHandler(msg *SGNet.Message) {
	if msg.Sess.UserData == nil {
		log.Info("掉线的玩家标识数据丢失")
		return
	}
	player := msg.Sess.UserData.(IPlayer)
	sceneServer.RemovePlayer(player.GetUserId())
	//如果游戏房间内只剩下机器人了销毁房间
	for _, player := range sceneServer.Players {
		if !player.IsRobot() {
			return
		}

	}
	for _, player := range sceneServer.Players {
		if player.IsRobot() {
			player.(*ScenePlayer).AIUnit.Destory()
		}

	}
	sceneServer.Destory()
}
